/*******************************************************************************
 * Copyright (c) 2008, 2009 Fabio Mauro - Alberto Terraneo.
 * Permission is granted to copy, distribute and/or modify this document
 * under the terms of the GNU Free Documentation License, Version 1.2
 * or any later version published by the Free Software Foundation.
 *     
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied 
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 * See the GNU Free Documentation License for more details.
 *     
 * You should have received a copy of the GNU Free Documentation 
 * License along with this distribution; if not, send a email to authors:
 * aterraneo <at> users.sourceforge.net
 * bigmoby09 <at> users.sourceforge.net
 *******************************************************************************/
package it.blueocean.acanto.web.platform.components.tabs.tabpanel.container;

import it.blueocean.acanto.web.platform.components.tabs.tabpanel.components.DynamicButtons;

import java.util.List;

import org.apache.wicket.Component;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import org.apache.wicket.extensions.markup.html.tabs.ITab;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.Loop;
import org.apache.wicket.markup.html.list.Loop.LoopItem;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.security.checks.ISecurityCheck;
import org.apache.wicket.security.checks.LinkSecurityCheck;
import org.apache.wicket.security.components.SecureComponentHelper;
import org.apache.wicket.security.extensions.markup.html.tabs.ISecureTab;

public class CustomSecureButtonPanel extends Panel
{
	private static final long serialVersionUID = -2983918098545268696L;

	/**
	 * id used for child panels
	 */
	public static final String BUTTONS_CONTAINER_PANEL_ID = "buttons-container";
	
	public static final String BUTTONS_PANEL_ID = "buttons-panel";

	public static final String LINK_BUTTON_ID = "link-button";

	public static final String TITLE_BUTTON_ID = "title-button";

	public static final String CONTENT_PANEL_ID = "content-panel";
	
	/**
	 * Lista dei diversi bottoni contenuti nel componente
	 */
	private List<DynamicButtons> buttons;

	/**
	 * 
	 * @param id
	 * @param buttonList
	 */
	public CustomSecureButtonPanel(String id, List<DynamicButtons> buttonList)
	{
		super(id, new Model<Integer>(new Integer(-1)));
		
		setOutputMarkupId(true);

		setVersioned(false);

		if(buttonList == null)
		{
			throw new IllegalArgumentException("argument [tabs] cannot be null");
		}

		setButtons(buttonList);

		WebMarkupContainer buttonsContainer = new WebMarkupContainer(BUTTONS_CONTAINER_PANEL_ID)
		{
			private static final long serialVersionUID = 1L;

			protected void onComponentTag(ComponentTag tag)
			{
				super.onComponentTag(tag);
				tag.put("class", BUTTONS_CONTAINER_PANEL_ID);
			}
		};
		
		buttonsContainer.add(createButton(BUTTONS_PANEL_ID, buttons));
		
		add(buttonsContainer);
	}

	private Loop createButton(String id, final List<DynamicButtons> buttons)
	{
		return new Loop(id, buttons.size())
		{
			private static final long serialVersionUID = 1L;

			protected void populateItem(LoopItem item)
			{
				int index = item.getIteration();

				DynamicButtons button = buttons.get(index);

				WebMarkupContainer titleLink = newLink(LINK_BUTTON_ID, index);
				
				titleLink.add(newButtonTitle(TITLE_BUTTON_ID, button.getTitle(), index));

				item.add(titleLink);
			}	
			
			@Override
			protected LoopItem newItem(int iteration)
			{
				return newTabContainer(iteration);
			}
		};
	}
	
	private LoopItem newTabContainer(int tabIndex)
	{
		return new LoopItem(tabIndex)
		{
			private static final long serialVersionUID = 1L;

			protected void onComponentTag(ComponentTag tag)
			{
				super.onComponentTag(tag);
				String cssClass = (String) tag.getString("class");
				if(cssClass == null)
				{
					cssClass = " ";
				}
				cssClass += " button" + getIteration();

				if(getIteration() == getSelectedTab())
				{
					cssClass += " selected";
				}
				if(getIteration() == getButtons().size() - 1)
				{
					cssClass += " last";
				}
				tag.put("class", cssClass.trim());
			}
		};
	}

	// @see org.apache.wicket.Component#onAttach()
	protected void onBeforeRender()
	{
		super.onBeforeRender();
		if(!hasBeenRendered() && getSelectedTab() == -1)
		{
			// select the first button by default
			setSelectedButton(0);
		}
	}

	/**
	 * @return list of button that can be used by the user to add/remove/reorder
	 *         button in the panel
	 */
	private final List<DynamicButtons> getButtons()
	{
		return buttons;
	}

	private final void setButtons(List<DynamicButtons> list)
	{
		this.buttons = list;
	}

	/**
	 * Factory method for button titles. Returned component can be anything that
	 * can attach to span tags such as a fragment, panel, or a label
	 * 
	 * @param titleId id of title component
	 * @param titleModel  model containing tab title
	 * @param index index of tab
	 * @return title component
	 */
	private Component newButtonTitle(String titleId, IModel<?> titleModel, int index)
	{
		return new Label(titleId, titleModel);
	}

	/**
	 * Factory method for links used to switch between tabs.
	 * 
	 * The created component is attached to the following markup. Label
	 * component with id: title will be added for you by the tabbed panel.
	 * 
	 * <pre>
	 *            &lt;a href=&quot;#&quot; wicket:id=&quot;link&quot;&gt;&lt;span wicket:id=&quot;title&quot;&gt;[[tab title]]&lt;/span&gt;&lt;/a&gt;
	 * </pre>
	 * 
	 * Example implementation:
	 * 
	 * <pre>
	 * protected WebMarkupContainer newLink(String linkId, final int index)
	 * {
	 * 	return new Link(linkId)
	 * 	{
	 * 		private static final long serialVersionUID = 1L;
	 * 
	 * 		public void onClick()
	 * 		{
	 * 			setSelectedTab(index);
	 * 		}
	 * 	};
	 * }
	 * </pre>
	 * 
	 * @param linkId
	 *            component id with which the link should be created
	 * @param index
	 *            index of the tab that should be activated when this link is
	 *            clicked. See {@link #setSelectedButton(int)}.
	 * @return created link component
	 */
	private WebMarkupContainer newLinkFromButtonPanel(String linkId, final int index)
	{
		return new AjaxFallbackLink<Object>(linkId)
		{
			private static final long serialVersionUID = 1L;

			public void onClick(AjaxRequestTarget target)
			{
				setSelectedButton(index);
				
				if(target != null)
				{
					target.addComponent(CustomSecureButtonPanel.this);
				}
				
				onAjaxUpdate(target);
			}
		};
	}

	/**
	 * sets the selected tab
	 * 
	 * @param index
	 *            index of the tab to select
	 * 
	 */
	private void setSelectedButton(int index)
	{
		if(index < 0 || index >= getButtons().size())
		{
			throw new IndexOutOfBoundsException();
		}

		setDefaultModelObject(new Integer(index));

		DynamicButtons buttons = (DynamicButtons) getButtons().get(index);

		// ottengo il pannello di bottoni associati al tab di riferimento
		Panel buttonsContainerPanel = buttons.getPanel(CONTENT_PANEL_ID);

		if(buttonsContainerPanel == null)
		{
			throw new WicketRuntimeException("ITab.getPanel() returned null. TabbedPanel [" + getPath()
					+ "] ITab index [" + index + "]");
		}

		if(!buttonsContainerPanel.getId().equals(CONTENT_PANEL_ID))
		{
			throw new WicketRuntimeException(
					"ITab.getPanel() returned a panel with invalid id ["
							+ buttonsContainerPanel.getId()
							+ "]. You must always return a panel with id equal to the provided panelId parameter. TabbedPanel ["
							+ getPath() + "] ITab index [" + index + "]");
		}

		if(get(CONTENT_PANEL_ID) == null)
		{
			add(buttonsContainerPanel);
		}
		else
		{
			replace(buttonsContainerPanel);
		}
	}

	/**
	 * @return index of the selected tab
	 */
	private final int getSelectedTab()
	{
		return ((Integer) getDefaultModelObject()).intValue();
	}

	/*
	 * ##########################################################################
	 * #################################################
	 */

	/**
	 * Fabio Mauro : Implemented by SecureTabbedPanel
	 * 
	 * 
	 * Adds an {@link ISecurityCheck} to {@link ISecureTab}s
	 * 
	 * @see org.apache.wicket.extensions.markup.html.tabs.TabbedPanel#newLink(java.lang.String,
	 *      int)
	 */
	@SuppressWarnings("unchecked")
	private WebMarkupContainer newLink(String linkId, int index)
	{
		Link link = (Link) newLinkFromButtonPanel(linkId, index);

		Class panelClass = getButtonClass(index);
		// We are using a LinkSecurityCheck instead of a ContainerSecurityCheck
		// because it operates on classes instead of instances.
		if(panelClass != null)
			SecureComponentHelper.setSecurityCheck(link, new LinkSecurityCheck(link, panelClass));
		// we can only set the check if we have a class, we could use
		// getPanel("dummy") and get the class from that but then we would
		// create some serious overhead instantiating panels twice.
		return link;
	}

	/**
	 * Fabio Mauro : Implemented by SecureTabbedPanel
	 * 
	 * 
	 * Gets the class of the panel. Note that it needs {@link ISecureTab}s for
	 * this.
	 * 
	 * @param tabIndex
	 *            the index of the tab
	 * @return the class or null if the tab at the index is not an ISecureTab
	 */
	@SuppressWarnings("unchecked")
	private Class getButtonClass(int tabIndex)
	{
		ITab tab = (ITab) getButtons().get(tabIndex);
		if(tab instanceof ISecureTab)
			return ((ISecureTab) tab).getPanel();
		return null;
	}
	
	/**
	 * A template method that lets users add additional behavior when ajax update occurs. This
	 * method is called after the current tab has been set so access to it can be obtained via
	 * {@link #getSelectedTab()}.
	 * <p>
	 * <strong>Note</strong> Since an {@link AjaxFallbackLink} is used to back the ajax update the
	 * <code>target</code> argument can be null when the client browser does not support ajax and
	 * the fallback mode is used. See {@link AjaxFallbackLink} for details.
	 * 
	 * @param target
	 *            ajax target used to update this component
	 */
	protected void onAjaxUpdate(AjaxRequestTarget target)
	{
	}
}
